package com.wan.core.strategy;

import cn.hutool.core.lang.ClassScanner;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.wan.core.strategy.selector.Selector;

import java.lang.reflect.Modifier;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import java.util.stream.Collectors;

/**
 * 策略池
 */
@SuppressWarnings({"unchecked", "rawtypes"})
public class StrategyPool {
    private static final Log log = LogFactory.get();
    private static final Map<Class<?>, StrategySelectorCreator<?, ?, ?>> creatorMap = new ConcurrentHashMap<>();
    private static String[] scanPackages;

    public static void preLoad(String... scanPackages) {
        creatorMap.clear();
        StrategyPool.scanPackages = scanPackages;
        try {
            /*
             * 这版不依赖spring容器
             */
            Set<Class<?>> classes = new HashSet<>();
            for (String scanPackage : scanPackages) {
                classes.addAll(ClassScanner.scanAllPackageByAnnotation(scanPackage, Strategy.class));
            }
            for (Class<?> aClass : classes) {
                StrategySelectorCreator<?, ?, ?> creator = loadStrategies(aClass);
                if (creator != null) {
                    creatorMap.put(aClass, creator);
                }
            }
        } catch (Exception e) {
            throw new StrategyLoadException(e);
        }

    }

    private static StrategySelectorCreator<?, ?, ?> loadStrategies(Class<?> superInterface) {
        Strategy strategy = superInterface.getAnnotation(Strategy.class);
        if (strategy == null) {
            return null;
        }
        StrategySelectorCreator<?, ?, ?> creator = ReflectUtil.newInstance(strategy.creator());
        Set<Class<?>> classSet = new HashSet<>();
        switch (strategy.scanType()){
            case NONE:
                break;
            case ALL:
                if(scanPackages != null && scanPackages.length > 0){
                    for (String scanPackage : scanPackages) {
                        classSet.addAll(ClassScanner.scanPackageBySuper(scanPackage, superInterface));
                    }
                    break;
                }
                //未设置全局扫描路径，往下执行 ↓↓
            case CUSTOM:
                String name = superInterface.getPackage().getName();
                int length = strategy.scanPackages().length;
                if (length > 0) {
                    for (String scanPackage : strategy.scanPackages()) {
                        classSet.addAll(ClassScanner.scanPackageBySuper(scanPackage, superInterface));
                    }
                } else {
                    classSet.addAll(ClassScanner.scanPackageBySuper(name, superInterface));
                }
                break;
        }
        List collect = classSet.stream()
                .filter(c-> !Modifier.isInterface(c.getModifiers()) && !Modifier.isAbstract(c.getModifiers()))
                .map(ReflectUtil::newInstance).collect(Collectors.toList());
        creator.init(collect);
        return creator;
    }

    /**
     * 获取一个策略
     *
     * @param cls     指定的类型
     * @param k       键
     * @param tryLoad 不存在是否尝试加载
     * @return
     */
    public static <K, T> T getStrategy(Class<T> cls, K k, boolean tryLoad) {
        if (cls.getAnnotation(Strategy.class) == null) {
            log.warn("该类上未配置指定注解Strategy -> {}", cls.getName());
            return null; //代理一个空对象回去？
        }
        StrategySelectorCreator<?, ?, ?> strategySelectorCreator = getCreator(cls);
        //尝试加载
        if (strategySelectorCreator == null && tryLoad) {
            strategySelectorCreator = loadStrategies(cls);
            if (strategySelectorCreator != null) {
                creatorMap.put(cls, strategySelectorCreator);
            }
        }
        if (strategySelectorCreator == null) {
            return null;
        }
        Selector<K, T> selector = (Selector<K, T>) strategySelectorCreator.getSelector();
        Optional<T> optional = selector.get(k);
        return optional.orElse(null);
    }

    public static <K, T> T getStrategy(Class<T> interfaceCls, K k) {
        return getStrategy(interfaceCls, k, true);
    }

    public static <K, T> T getStrategy(Class<T> interfaceCls, boolean tryLoad) {
        return getStrategy(interfaceCls, (K) null, tryLoad);
    }

    public static <K, T> T getStrategy(Class<T> interfaceCls) {
        return getStrategy(interfaceCls, (K) null, true);
    }

    private static StrategySelectorCreator<?, ?, ?> getCreator(Class<?> cls) {
        return creatorMap.get(cls);
    }

    /**
     * 添加策略
     */
    public static <T, K, I extends T> void addStrategy(Class<T> interfaceCls, K k, I object) {
        StrategySelectorCreator<?, ?, ?> creator = getCreator(interfaceCls);
        if(creator == null){
            log.warn("未找到对应策略的处理 -> {}", interfaceCls.getName());
            return;
        }
        Selector selector = creator.getSelector();
        selector.add(k, object);
    }

    /**
     * 移除策略
     */
    public static <T, K, I extends T> void removeStrategy(Class<T> interfaceCls, K k, I object) {
        StrategySelectorCreator<?, ?, ?> creator = getCreator(interfaceCls);
        if(creator == null){
            log.warn("未找到对应策略的处理 -> {}", interfaceCls.getName());
            return;
        }
        Selector selector = creator.getSelector();
        selector.remove(k, object);
    }
}
